package com.chenwc.wso2.wso2esb;

import com.chenwc.file.Decompression;
import com.chenwc.httpclient.RestMock;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * wso2car包操作工具类
 *
 * @author chenwc
 * @date 2023/8/31 22:15
 */
public class Wso2CarFileUtil {

    private final static Logger log = LoggerFactory.getLogger(Wso2CarFileUtil.class);

    /**
     * 上传car包
     *
     * @param wso2Properties wso2属性
     * @param carFile        car包文件路径
     * @return 上传car包的结果，上传成功后，每隔一秒循环获取15次car包列表，15次都超时默认失败
     */
    public static boolean uploadCarFile(Wso2Properties wso2Properties, File carFile) {
        if (null == carFile || !carFile.exists()) {
            log.warn("文件不存在！");
            return false;
        }
        if (!carFile.getName().endsWith("car")) {
            log.warn("请上传 .car 结尾的 car 文件！");
            return false;
        }
        //car包应用列表
        List<Map<String, String>> carbonAppList = Wso2CarFileUtil.getCarbonAppList(wso2Properties);
        //car文件里面的appName
        String uploadCarbonAppName = Decompression.getUploadCarbonAppName(carFile).get("appName");
        //判断是否已经存在该car包
        String carbonAppName = Wso2CarFileUtil.getCarbonAppNameAndVersion(carbonAppList, uploadCarbonAppName);
        if (StringUtils.isNotEmpty(carbonAppName)) {
            log.warn("WSO2 ESB 已存在名称为：{} 的工件！", uploadCarbonAppName);
            return false;
        }
        log.info("开始上传工件....");
        String token = getToken(wso2Properties.getGetTokenUrl());
        login(wso2Properties, token);
        String url = wso2Properties.getUploadCarFileUrl() + "?X-CSRF-Token=" + token;
        Map<String, String> header = new HashMap<>();
        RestMock.sendPostByFileAndFormBody(url, header, new HashMap<>(), carFile);

        int i = 0;
        do {
            //获取碳应用列表
            carbonAppList.clear();
            carbonAppList = Wso2CarFileUtil.getCarbonAppList(wso2Properties);
            i++;
            log.info("刷新碳应用列表：{}", carbonAppList);
            try {
                Thread.sleep(1000);
                log.debug("等待car包发布成功....");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //不断刷新，判断是否已经上传成功
            carbonAppName = Wso2CarFileUtil.getCarbonAppNameAndVersion(carbonAppList, uploadCarbonAppName);
        } while (!StringUtils.isNotEmpty(carbonAppName) && i < 20);
        if (i < 20) {
            log.info("工件上传成功！");
            return true;
        } else {
            log.warn("工件上传失败！");
            return false;
        }
    }

    /**
     * 获取工件appName+appVersion
     *
     * @param carbonAppList 碳应用列表
     * @param appName       需要删除的碳应用名称，输入唯一标识
     * @return 删除工件时的appName参数
     */
    public static String getCarbonAppNameAndVersion(List<Map<String, String>> carbonAppList, String appName) {
        if (StringUtils.isEmpty(appName)) {
            log.warn("appName不能为空！");
            return "";
        }
        List<Map<String, String>> deleteCarbonApp = carbonAppList.stream().filter(
                s -> s.get("appName").contains(appName)).collect(Collectors.toList());
        String carbonAppNameAndVersion = "";
        if (deleteCarbonApp.size() > 1) {
            log.debug("根据条件 appName：" + appName + " 查出来多个结果，请重新输入查询条件");
        } else if (deleteCarbonApp.size() <= 0) {
            log.debug("根据条件 appName：" + appName + " 查询无结果，请重新输入查询条件");
        } else {
            carbonAppNameAndVersion = deleteCarbonApp.get(0).get("appName") + "_" + deleteCarbonApp.get(0).get("appVersion");
        }
        return carbonAppNameAndVersion;
    }

    /**
     * 删除工件
     *
     * @param wso2Properties wso2属性
     * @param carMap         工件名称
     * @param isWso2Esb 是否wso2esb，wso2esb 5.x为true，wso2ei 6.x为否
     */
    public static boolean deleteCarFile(Wso2Properties wso2Properties, Map<String, String> carMap, boolean isWso2Esb) {
        if (null == carMap || carMap.isEmpty()) {
            log.warn("待删除工件名称不能为空！");
            return false;
        }
        //car包应用列表
        List<Map<String, String>> carbonAppList = Wso2CarFileUtil.getCarbonAppList(wso2Properties);
        //判断是否已经存在该car包
        String carbonAppName = Wso2CarFileUtil.getCarbonAppNameAndVersion(carbonAppList, carMap.get("appName"));
        if (StringUtils.isEmpty(carbonAppName)) {
            log.warn("WSO2 ESB 不存在名称为：{} 的工件！", carMap.get("appName"));
            return false;
        }
        log.info("开始删除名称为：" + carMap.get("appName") + " 的工件！");
        String token = getToken(wso2Properties.getGetTokenUrl());
        login(wso2Properties, token);
        String url = "";
        if (isWso2Esb){
            url = wso2Properties.getDeleteCarFileUrl() + "?appName=" + carbonAppName;
        }
        else {
            url = wso2Properties.getWso2Host() + "/carbon/carbonapps/delete_artifact.jsp?appName=" + carbonAppName;
        }
        Map<String, String> formMap = new HashMap<>();
        formMap.put("X-CSRF-Token", token);
        RestMock.sendPostByFormBody(url, new HashMap<>(), formMap);

        int i = 0;
        do {
            //获取碳应用列表
            carbonAppList.clear();
            carbonAppList = Wso2CarFileUtil.getCarbonAppList(wso2Properties);
            i++;
            log.info("刷新碳应用列表：{}", carbonAppList);
            try {
                Thread.sleep(1000);
                log.debug("等待car包删除成功....");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //不断刷新，判断是否已经上传成功
            carbonAppName = Wso2CarFileUtil.getCarbonAppNameAndVersion(carbonAppList, carMap.get("appName"));
        } while (!StringUtils.isEmpty(carbonAppName) && i < 20);
        if (i < 20) {
            log.info("工件删除成功！");
            return true;
        } else {
            log.warn("工件删除失败！");
            return false;
        }
    }

    /**
     * 下载工件
     *
     * @param wso2Properties wso2属性
     * @param carMap         工件名称
     */
    public static void downloadCarFile(Wso2Properties wso2Properties, Map<String, String> carMap) {
        if (null == carMap || carMap.isEmpty()) {
            log.warn("待下载工件名称不能为空！");
            return;
        }
        //car包应用列表
        List<Map<String, String>> carbonAppList = Wso2CarFileUtil.getCarbonAppList(wso2Properties);
        //判断是否已经存在该car包
        String carbonAppName = Wso2CarFileUtil.getCarbonAppNameAndVersion(carbonAppList, carMap.get("appName"));
        if (StringUtils.isEmpty(carbonAppName)) {
            log.warn("WSO2 ESB 不存在名称为：{} 的工件！", carMap.get("appName"));
            return;
        }
        String token = getToken(wso2Properties.getGetTokenUrl());
        login(wso2Properties, token);
        String url = wso2Properties.getDownloadCarFileUrl() + "?cappName=" + carbonAppName;
        String saveFile = wso2Properties.getSaveFilePath() + carbonAppName + ".car";
        RestMock.downloadFileByGet(url, saveFile);
        log.info("工件下载成功！");
    }

    /**
     * 获取碳应用列表
     *
     * @param wso2Properties wso2属性
     * @return 碳应用列表
     */
    public static List<Map<String, String>> getCarbonAppList(Wso2Properties wso2Properties) {

        List<Map<String, String>> carbonAppList = new ArrayList<>();

        String token = getToken(wso2Properties.getGetTokenUrl());
        login(wso2Properties, token);

        Map<String, String> parameter = new HashMap<>();
        parameter.put("region", "region1");
        parameter.put("item", "apps_list_menu");
        String resp = RestMock.sendGetByParameter(wso2Properties.getGetCarFileListUrl(), new HashMap<>(), parameter);

        Document myDoc = Jsoup.parse(resp);
        Element appTable = myDoc.getElementById("appTable");
        if (null != appTable) {
            Elements trs = appTable.getElementsByTag("tr");
            for (Element tr : trs) {
                if (tr.html().contains("application_info.jsp")) {
                    Elements tds = tr.getElementsByTag("td");
                    Map<String, String> carbonApp = new HashMap<>();
                    carbonApp.put("appName", tds.get(0).text());
                    carbonApp.put("appVersion", tds.get(1).text());
                    carbonAppList.add(carbonApp);
                    //log.info("appName: {}", tds.get(0).text());
                    //log.info("appVersion: {}", tds.get(1).text());
                }
            }
        }

        return carbonAppList;
    }

    /**
     * 登录wso2
     *
     * @param wso2Properties wso2属性
     * @param token          token
     */
    private static void login(Wso2Properties wso2Properties, String token) {
        Map<String, String> header = new HashMap<>();
        header.put("username", wso2Properties.getUsername());
        header.put("password", wso2Properties.getPassword());
        header.put("X-CSRF-Token", token);
        String url = wso2Properties.getLoginUrl() + "?" + RestMock.generateGetParameter(header);
        RestMock.sendPost(url, new HashMap<>());
    }

    /**
     * 获取X-CSRF-Token
     *
     * @param url url
     * @return X-CSRF-Token
     */
    private static String getToken(String url) {
        Map<String, String> header = new HashMap<>();
        header.put("Fetch-Csrf-Token", "1");
        String token = RestMock.sendPost(url, header);
        return token.split(":")[1];
    }
}
